package com.le.tester.sevice.impl;

import com.le.tester.common.Const;
import com.le.tester.common.enums.RedisKey;
import com.le.tester.common.enums.ResponseCode;
import com.le.tester.common.enums.StatusCode;
import com.le.tester.dao.CommentLikeMapper;
import com.le.tester.dto.CommentLikeDto;
import com.le.tester.entity.CommentLike;
import com.le.tester.handler.BusinessException;
import com.le.tester.sevice.CommentService;
import com.le.tester.utils.DateTimeUtilFor8;
import com.le.tester.utils.RedisUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 描述：评论的实现层
 */
@Service
public class CommentServiceImpl implements CommentService {

    private static final Logger LOG = LoggerFactory.getLogger(CommentServiceImpl.class);

    @Resource
    private CommentLikeMapper commentLikeMapper;

    @Autowired
    private RedisUtil redisUtil;


    private void saveLikeOrUnlike(CommentLikeDto commentLikeDto) {
        //hashKey
        BoundHashOperations<String, Object, Object> likeHashOps = redisUtil.boundHashOps(RedisKey.MAP_KEY_USER_LIKED.getCode());
        BoundHashOperations<String, Object, Object> countHashOps = redisUtil.boundHashOps(RedisKey.MAP_USER_LIKED_COUNT.getCode());
        //点赞数据的key
        String likeKey = commentLikeDto.getProductId() + Const.CONNECT_STR
                + commentLikeDto.getCommentId() + Const.CONNECT_STR + commentLikeDto.getPeopleId();
        //点赞数目数据的key
        String countKey = String.valueOf(commentLikeDto.getCommentId());
        //获取点赞数
        Long likeNum = this.getLikeNumForComment(commentLikeDto.getCommentId());
        AtomicLong atomicLong = new AtomicLong(likeNum);
        CommentLike commentLike = this.getCommentLikeByCommentIdPeopleId(commentLikeDto.getCommentId(), commentLikeDto.getPeopleId());
        //用户默认是没有点赞的，第一次点击是要点赞的，对于该评论进行点赞
        if (StatusCode.LIKE.getCode() == commentLikeDto.getLikeStatus() && null == commentLike) {
            //点赞,存进redis中的hash,被点赞的评论id加上评论人的id,
            likeHashOps.put(likeKey, commentLikeDto.getLikeStatus());
            //点赞数进行加一
            countHashOps.put(countKey, atomicLong.incrementAndGet());
        } else if (StatusCode.UNLIKE.getCode() == commentLikeDto.getLikeStatus()
                && null != commentLike && null == commentLike.getCancelTime()) {
            //进行点赞的取消(第一次没有取消)
            //取消点赞
            likeHashOps.put(likeKey, commentLikeDto.getLikeStatus());
            //点赞数据进行减一
            countHashOps.put(countKey, atomicLong.decrementAndGet());
        } else {
            throw new BusinessException(ResponseCode.ILLEGAL_ARGUMENT.getDesc());
        }
    }

    /**
     * 从redis中获取数据
     *
     * @param commentLikeDto:点赞数据传输
     * @return
     */
    public Map<String, List<CommentLikeDto>> commentLikeOrUnlike(CommentLikeDto commentLikeDto) {
        //把数据保存进数据库
        this.saveLikeOrUnlike(commentLikeDto);
        //点赞数据的key
        String likeKey = commentLikeDto.getProductId() + Const.CONNECT_STR
                + commentLikeDto.getCommentId() + Const.CONNECT_STR + commentLikeDto.getPeopleId();
        //点赞数目数据的key
        String countKey = String.valueOf(commentLikeDto.getCommentId());

        List<CommentLikeDto> commentLikeDtoList = new ArrayList<>();
        Map<String, List<CommentLikeDto>> resultMap = new HashMap<>();
        //获取hashKey中的值
        int likeStatus = (int) redisUtil.hget(RedisKey.MAP_KEY_USER_LIKED.getCode(), likeKey);
        long likeCount = Long.parseLong(String.valueOf(redisUtil.hget(RedisKey.MAP_USER_LIKED_COUNT.getCode(), countKey)));

        commentLikeDto.setLikeNum(likeCount);
        commentLikeDto.setLikeStatus(likeStatus);
        commentLikeDtoList.add(commentLikeDto);
        resultMap.put("commentLikeInfo", commentLikeDtoList);
        return resultMap;
    }

    private Date getExpireTime() {
        //加上一天
        LocalDateTime expireTime = LocalDateTime.now().plusDays(1).withHour(0).withMinute(0).withSecond(0).withNano(0);
        Instant instant = expireTime.atZone(ZoneId.systemDefault()).toInstant();
        return Date.from(instant);
    }

    //从redis中获取到值
    private List<CommentLike> getLikedInfoFromRedis() {
        Map<Object, Object> likeStatusInfo = redisUtil.hmget(RedisKey.MAP_KEY_USER_LIKED.getCode());
        Set<Object> keySet = likeStatusInfo.keySet();
        List<CommentLike> commentLikes = new ArrayList<>();
        for (Object keyItem : keySet) {
            String key = String.valueOf(keyItem);
            String[] strings = key.split("::");
            String productId = strings[0];
            String commentId = strings[1];
            String peopleId = strings[2];
            String likeKey = productId + Const.CONNECT_STR + commentId + Const.CONNECT_STR + peopleId;
            //获取点赞状态
            int likeStatus = (int) redisUtil.hget(RedisKey.MAP_KEY_USER_LIKED.getCode(), likeKey);
            //获取点赞的数目
            //long likeCount = Long.parseLong(String.valueOf(redisUtil.hget(RedisKey.MAP_USER_LIKED_COUNT.getCode(), commentId)));
            CommentLike commentLike = new CommentLike();
            commentLike.setLikeStatus(likeStatus);
            commentLike.setCommentId(Long.parseLong(commentId));
            commentLike.setPeopleId(Long.parseLong(peopleId));
            commentLike.setProductId(Long.parseLong(productId));
//            commentLike.setLikeNum(likeCount);
            commentLikes.add(commentLike);

            //存到 list 后从 Redis 中删除likeStatus
            redisUtil.hdel(RedisKey.MAP_KEY_USER_LIKED.getCode(), likeKey);
            if (null != redisUtil.hget(RedisKey.MAP_USER_LIKED_COUNT.getCode(), commentId)) {
                redisUtil.hdel(RedisKey.MAP_USER_LIKED_COUNT.getCode(), commentId);
            }

        }
        return commentLikes;
    }

    @Transactional
    public void transLikedInfoFromRedis2DB() {
        //获取点赞等信息
        List<CommentLike> likedInfo = this.getLikedInfoFromRedis();
        //还是要操作一下数据库的数据

        for (CommentLike commentLikeItem : likedInfo) {
            CommentLike commentLike = new CommentLike();
            //commentLike.setLikeNum(commentLikeItem.getLikeNum());
            commentLike.setProductId(commentLikeItem.getProductId());
            commentLike.setPeopleId(commentLikeItem.getPeopleId());
            commentLike.setCommentId(commentLikeItem.getCommentId());
            commentLike.setLikeStatus(commentLikeItem.getLikeStatus());
            commentLike.setCreateTime(new Date());
            if (StatusCode.LIKE.getCode() == commentLikeItem.getLikeStatus()) {
                commentLike.setLikeTime(new Date());
                commentLike.setUpdateTime(new Date());
            }
            if (StatusCode.UNLIKE.getCode() == commentLikeItem.getLikeStatus()) {
                commentLike.setCancelTime(new Date());
                commentLike.setUpdateTime(new Date());
            }
            //不要重复的插入点赞状态的数据
            CommentLike commentLikeDB = this.getCommentLikeByCommentIdPeopleId(commentLikeItem.getCommentId(), commentLikeItem.getPeopleId());
            if (null != commentLikeDB) {
                commentLikeMapper.updateByCommentIdPeopleId(commentLike);
                //throw new BusinessException(ResponseCode.ILLEGAL_ARGUMENT.getDesc());
            } else {
                commentLikeMapper.insert(commentLike);
            }
        }
    }

    @Scheduled(cron = "0 0 0/1 * * ?")
    public void scheduledMethod() {
        //将 Redis 里的点赞信息同步到数据库里
        LOG.info("定时任务开启：{}", DateTimeUtilFor8.time());
        this.transLikedInfoFromRedis2DB();
    }

    /**
     * 获取点赞数
     */
    private Long getLikeNumForComment(long commentId) {
        return commentLikeMapper.selectLikeNumByCommentId(commentId);
    }

    /**
     * 根据commentId和peopleId获取点赞信息
     */
    private CommentLike getCommentLikeByCommentIdPeopleId(long commentId, long peopleId) {
        return commentLikeMapper.selectCommentLikeByCommentIdPeopleId(commentId, peopleId);
    }
}
